﻿using Common;
using CommonModel;
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleTest
{
    class Program
    {
        #region 内部类
        private class Test
        {
            public int TestId { get; set; }
            public string Name { get; set; }
            public DateTime CreateDate { get; set; }
        }

        //Money
        private interface IMoney
        {
            bool IsSoMuch { get; set; }
        }
        private class Money : IMoney
        {
            public bool IsSoMuch { get; set; }
            public Money()
            {
                Console.WriteLine("Money已被构造！！！");
            }
        }

        //Car 依赖 Money
        private interface ICar
        {
            IMoney Money { get; set; }
            void Run();
        }

        private class Car : ICar
        {
            public IMoney Money { get; set; }
            public Car(IMoney money)
            {
                this.Money = money;
                Console.WriteLine("Car已被构造！");
            }

            public void Run()
            {
                throw new NotImplementedException();
            }
        }

        //House 依赖 Money
        private interface IHouse
        {
            IMoney Money { get; set; }
            void Live();
        }

        private class House : IHouse
        {
            public IMoney Money { get; set; }

            public House(IMoney money)
            {
                this.Money = money;
                Console.WriteLine("House已被构造！！！");
            }

            public void Live() { }
        }

        //Person 依赖 House、Car
        private interface IPerson
        {
            IHouse House { get; set; }
            ICar Car { get; set; }
            void Eat();
            void Sleep();
        }

        private class Person : IPerson
        {
            public IHouse House { get; set; }
            public ICar Car { get; set; }

            public Person(IHouse house, ICar car)
            {
                House = house;
                Car = car;
                Console.WriteLine("Person已被构造！！！");
            }

            public void Eat() { }

            public void Sleep() { }
        }
        #endregion

        static void Main(string[] args)
        {
            try
            {
                //TestThread();
                //TestMq();
                //TestRedis();
                //TestTask();
                //TestFtp();
                TestSimpleIoc();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"报错：{ex}");
            }

            Console.WriteLine("控制台程序已启动，输入一行即退出。");
            Console.ReadLine();
        }

        /// <summary>
        /// 测试简单IOC帮助类
        /// </summary>
        private static void TestSimpleIoc()
        {
            SimpleIocHelper.Register<IPerson, Person>();
            SimpleIocHelper.Register<IHouse, House>();
            SimpleIocHelper.Register<ICar, Car>();
            SimpleIocHelper.Register<IMoney, Money>();
            IPerson person = SimpleIocHelper.Resolve<IPerson>();
        }

        /// <summary>
        /// 测试Ftp
        /// </summary>
        private static void TestFtp()
        {
            FtpHelper ftpHelper = new FtpHelper("192.168.1.133", "Test", "123456", "21", "");
            ftpHelper.UploadFile(@"D:\FTP\SJYHDL\20220527.del");
        }

        /// <summary>
        /// 测试Task
        /// </summary>
        private static void TestTask()
        {
            //https://www.cnblogs.com/zhaoshujie/p/11082753.html
            #region 创建任务
            #region 无返回值的线程方法
            var t1 = new Task(() => TaskOne("Task 1"));
            t1.Start();

            var t2 = Task.Run(() => TaskOne("Task 2"));

            //标记为长时间运行任务,则任务不会使用线程池,而在单独的线程中运行。
            var t3 = Task.Factory.StartNew(() => TaskOne("Task 3"), TaskCreationOptions.LongRunning);

            Task.WaitAll(t1, t2, t3);
            #endregion
            #region 带返回值的线程方法
            string param = "";
            Task<string> t4 = new Task<string>(() => { return TaskThree(param); });
            t4.Start();
            string result = t4.Result;
            #endregion
            #endregion
        }

        /// <summary>
        /// 测试Redis
        /// </summary>
        public static void TestRedis()
        {
            //RedisCacheBll redisCacheBll = new RedisCacheBll();
            //DateTime now = DateTime.Now;
            //Stopwatch sw = new Stopwatch();
            //sw.Start();
            //Console.WriteLine($"开始新增Redis记录");
            //int count = 10000;//ServiceStack.Redis免费版存在每小时6000并发量的限制，需修改源码解除限制，可用notepad插件直接修改：https://www.cnblogs.com/blogzys/p/10414578.html (查找可能存在两处，全部替换即可)
            //for (int i = 0; i < count; i++)
            //{
            //    bool flag = redisCacheBll.Add(i.ToString(), new Test() { TestId = i, Name = "名字", CreateDate = now }, DateTime.Now.AddMinutes(5));
            //}
            //sw.Stop();
            //TimeSpan ts2 = sw.Elapsed;
            //Console.WriteLine($"新增Redis[{count}]记录总共花费{ts2.TotalMilliseconds}ms.");
            //测试结果：
            //新增Redis[10000]记录总共花费15556.3755ms.
            //新增Redis[10000]记录总共花费11558.6255ms.
            //新增Redis[10000]记录总共花费10732.2804ms.
            //新增Redis[10000]记录总共花费14944.7764ms.
            //新增Redis[10000]记录总共花费14473.6709ms.
            //新增Redis[10000]记录总共花费15151.358ms.
            //var obj = Bll.RedisCacheHelper.GetList<string>("*UserInfo_*");
        }

        /// <summary>
        /// Mq测试
        /// </summary>
        public static void TestMq()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            //耗时巨大的代码
            for (int i = 0; i < 500; i++)//本机器达到每秒230次的访问压力
            {
                MqMessage mqMessage = new MqMessage();
                mqMessage.MessageId = Guid.NewGuid().ToString("N");
                mqMessage.MessageQueue = "Test.One";
                mqMessage.MessageTitle = "Test";
                mqMessage.MessageBody = "Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。Test.压力测试经发局放了卡房间垃圾袋方法就禄口街道，jfkdjfkkjfakl;djfakljjkjkl;j,艰苦奋斗扣费的。房间读卡路径。";
                WebApiCallerHr.HttpPost("http://127.0.0.1:8086/api/Mq/SendMessage", mqMessage.ToJson());
            }

            sw.Stop();
            TimeSpan ts2 = sw.Elapsed;
            Console.WriteLine("Stopwatch总共花费{0}ms.", ts2.TotalMilliseconds);
            Console.WriteLine("Mq压力测试完毕,任意键结束");
            Console.ReadKey();
        }

        /// <summary>
        /// 测试C#线程Thread
        /// </summary>
        public static void TestThread()
        {
            #region 注释
            //*************************************线程的常用属性*************************************
            //CurrentContext 获取线程正在其中执行的当前上下文。
            //CurrentThread 获取当前正在运行的线程。
            //ExecutionContext 获取一个 ExecutionContext 对象，该对象包含有关当前线程的各种上下文的信息。
            //IsAlive 获取一个值，该值指示当前线程的执行状态。
            //IsBackground 获取或设置一个值，该值指示某个线程是否为后台线程。
            //IsThreadPoolThread 获取一个值，该值指示线程是否属于托管线程池。
            //ManagedThreadId 获取当前托管线程的唯一标识符。
            //Name 获取或设置线程的名称。
            //Priority 获取或设置一个值，该值指示线程的调度优先级。
            //****************************************************************************************
            //*************************************线程的常用方法 * ************************************
            //Abort()         终止本线程。
            //GetDomain()     返回当前线程正在其中运行的当前域。
            //GetDomainId()   返回当前线程正在其中运行的当前域Id。
            //GetApartmentState()       默认值是MTA，也就是多线程模式的
            //Interrupt()     中断处于 WaitSleepJoin 线程状态的线程。
            //Join()  已重载。 阻塞调用线程，直到某个线程(调用此方法的线程)终止时为止。
            //Resume()    继续运行已挂起的线程。
            //Start()     执行本线程。
            //Suspend()   挂起当前线程，如果当前线程已属于挂起状态则此不起作用
            //Sleep()     把正在运行的线程挂起一段时间。
            ////****************************************************************************************
            #endregion
            Thread thread = new Thread(new ParameterizedThreadStart(TaskOne));
            thread.Start("测试1");//默认IsBackground为False，前台线程

            ThreadPool.SetMinThreads(2, 2);
            ThreadPool.SetMaxThreads(20, 20);
            ThreadPool.QueueUserWorkItem(TaskOne, "测试1");//线程池默认IsBackground为True，后台线程

            CallWithTimeout(TaskFour, 3000);
        }

        #region 私有方法
        /// <summary>
        /// 时间范围内调用方法
        /// </summary>
        /// <param name="action"></param>
        /// <param name="timeoutMilliseconds"></param>
        /// <returns></returns>
        static string CallWithTimeout(Func<string> function, int timeoutMilliseconds)
        {
            string result = "";
            Thread threadToKill = null;
            Func<string> wrappedAction = () =>
            {
                threadToKill = Thread.CurrentThread;
                return function();
            };

            IAsyncResult asyncResult = wrappedAction.BeginInvoke(null, null);
            //IAsyncResult.AsyncWaitHandle 属性： 当异步调用完成时 WaitHandle 会收到信号，而你可以通过调用 WaitOne 方法来等待它。
            if (asyncResult.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
            {
                result = wrappedAction.EndInvoke(asyncResult);
                asyncResult.AsyncWaitHandle.Close();
                asyncResult.AsyncWaitHandle.Dispose();
            }
            else
            {
                threadToKill.Abort();
                asyncResult.AsyncWaitHandle.Close();
                asyncResult.AsyncWaitHandle.Dispose();
            }

            return result;
        }

        #region Thread  返回参数 https://blog.csdn.net/weixin_45414738/article/details/103727435
        /// <summary>
        /// 又要结果 要不阻塞 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        public Func<T> ThreadWithReturn<T>(Func<T> func)
        {
            var t = default(T);
            var thread = new Thread(() =>
            {
                t = func.Invoke();
            });
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            return () =>
            {
                thread.Join();
                return t;
            };
        }
        //调用此方法
        public string invoking(string sWhere)
        {
            var func = this.ThreadWithReturn<string>(() =>
            {
                return Count(sWhere);
            });
            return func.Invoke();
        }
        //工作类
        public string Count(string sWhere)
        {
            for (int i = 0; i < 100000; i++)
            {
                Console.WriteLine(sWhere);
            }
            return sWhere;
        }
        #endregion

        /// <summary>
        /// 任务1
        /// </summary>
        /// <param name="param"></param>
        private static void TaskOne(object param)
        {
            int count = 5;
            while (count > 0)
            {
                FileLogHelper.DebugAdd($@"输出入参：{param}
ManagedThreadId：{Thread.CurrentThread.ManagedThreadId}
IsThreadPoolThread：{Thread.CurrentThread.IsThreadPoolThread}
IsBackground：{Thread.CurrentThread.IsBackground}
ApartmentState：{Thread.CurrentThread.GetApartmentState()}
Priority：{Thread.CurrentThread.Priority}
ThreadState：{Thread.CurrentThread.ThreadState}", "多线程测试1");
                count--;
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 任务2
        /// </summary>
        private static void TaskTwo()
        {
            int count = 5;
            while (count > 0)
            {
                FileLogHelper.DebugAdd($@"ManagedThreadId：{Thread.CurrentThread.ManagedThreadId}
IsThreadPoolThread：{Thread.CurrentThread.IsThreadPoolThread}
IsBackground：{Thread.CurrentThread.IsBackground}
ApartmentState：{Thread.CurrentThread.GetApartmentState()}
Priority：{Thread.CurrentThread.Priority}
ThreadState：{Thread.CurrentThread.ThreadState}", "多线程测试1");
                count--;
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 任务3
        /// </summary>
        private static string TaskThree(object param)
        {
            int count = 5;
            while (count > 0)
            {
                FileLogHelper.DebugAdd($@"输出入参：{param}
ManagedThreadId：{Thread.CurrentThread.ManagedThreadId}
IsThreadPoolThread：{Thread.CurrentThread.IsThreadPoolThread}
IsBackground：{Thread.CurrentThread.IsBackground}
ApartmentState：{Thread.CurrentThread.GetApartmentState()}
Priority：{Thread.CurrentThread.Priority}
ThreadState：{Thread.CurrentThread.ThreadState}", "多线程测试1");
                count--;
                Thread.Sleep(1000);
            }

            return "任务3执行完毕";
        }

        /// <summary>
        /// 任务4
        /// </summary>
        private static string TaskFour()
        {
            int count = 5;
            while (count > 0)
            {
                FileLogHelper.DebugAdd($@"ManagedThreadId：{Thread.CurrentThread.ManagedThreadId}
IsThreadPoolThread：{Thread.CurrentThread.IsThreadPoolThread}
IsBackground：{Thread.CurrentThread.IsBackground}
ApartmentState：{Thread.CurrentThread.GetApartmentState()}
Priority：{Thread.CurrentThread.Priority}
ThreadState：{Thread.CurrentThread.ThreadState}", "多线程测试1");
                count--;
                Thread.Sleep(1000);
            }

            return "任务4执行完毕";
        }
        #endregion
    }
}
